package com.feng.service.impl;

import cn.hutool.db.Page;
import com.alibaba.fastjson.JSON;
import com.feng.XadminSpringBootApplication;
import com.feng.controller.CreateES;
import com.feng.dto.UserDto;
import com.feng.entity.User;
import com.feng.service.ESService;
import com.feng.vo.PageVo;
import com.feng.vo.ResultVo;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: 丰
 * @date: 2023/1/31 10:32
 */
@Service
public class ESServiceImpl<T> implements ESService<T> {

    @Autowired
    private RestHighLevelClient client;


    @Override
    public ResultVo<List<T>> getDoc(PageVo condition, String doc, Class<T> clazz) throws IOException {
        // user
        if (doc.equals("user_doc")){
            return getUserDoc(condition, doc, "username", clazz);
        }
        // product
        else if (doc.equals("product_doc")){
            return getUserDoc(condition, doc,  "name", clazz);
        }
        // news
        else if (doc.equals("news_doc")){
            return getUserDoc(condition, doc,  "name", clazz);
        }
        // info
        else if (doc.equals("info_doc")){
            return null;
        }
        else {
            return null;
        }
    }

    @Override
    public void modifyDoc(String doc) {
        // user
//        if (doc.equals("user_doc")){
//            try {
//                createES.modifyUserDoc();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
//        // product
//        else if (doc.equals("product_doc")){
//            try {
//                createES.modifyProductDoc();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
//        // news
//        else if (doc.equals("news_doc")){
//            try {
//                createES.modifyNewsDoc();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
    }

    /**
     * @param condition 分页、查询条件
     * @param doc 指定文档
     * @param target 需要高亮的字段
     * @param clazz 分装的实体类
     */
    private ResultVo<List<T>> getUserDoc(PageVo condition, String doc, String target, Class<T> clazz) throws IOException {
        // 获取当前文档的数据总数
        CountRequest countRequest = new CountRequest(doc);
        int count = (int) client.count(countRequest, RequestOptions.DEFAULT).getCount();

        SearchRequest searchRequest = new SearchRequest(doc);
        // 构建搜索条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 高亮  ，以哪个字段里面构建高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field(target);
        highlightBuilder.requireFieldMatch(false);
        highlightBuilder.preTags("<span  style='color:red'>");
        highlightBuilder.postTags("</span>");
        // 将高亮的条件放到   搜索条件对象里面
        sourceBuilder.highlighter(highlightBuilder);

        if (condition.getSearch() != null){
            MatchQueryBuilder termQueryBuilder = QueryBuilders.matchQuery(target, condition.getSearch());
//            WildcardQueryBuilder termQueryBuilder = QueryBuilders.wildcardQuery(target, "*" + condition.getSearch() + "*");
            // 将精确查询的对象放到   搜索对象里面
            sourceBuilder.query(termQueryBuilder);
        }else {
            MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
            sourceBuilder.query(matchAllQueryBuilder);
        }
        //分页查询
        sourceBuilder.from((condition.getPage() - 1) * condition.getLimit());
        sourceBuilder.size(condition.getLimit());

//        if (condition.getStart() != null && condition.getEnd() != null){
//            // 时间区间查询
//            RangeQueryBuilder rangequerybuilder = QueryBuilders
//                    .rangeQuery("create_time")
//                    .from(condition.getStart()).to(condition.getEnd());
//            sourceBuilder.query(rangequerybuilder);
//        }

        // 放到数据库对象里面
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

        //        解析搜索出来的数据，变为前端的格式，
        List<T> list = new ArrayList<>();
        for(SearchHit documentFields :searchResponse.getHits().getHits()){
//            解析高亮的字段
            Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
            Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();

            HighlightField title = highlightFields.get(target);
//            得到原来的字段
            if(title != null){
                Text[] fragments = title.fragments();  // 得到高亮字段的值
                String n_title = "";
                for (Text text:fragments){
                    n_title += text;
                }
                sourceAsMap.put(target, n_title);//替换原来的字段
            }

            T t = JSON.parseObject(JSON.toJSONString(sourceAsMap), clazz);
            list.add(t);
        }
        return ResultVo.success(list).code(0).count(count);
    }
}
